package net.borlis.sample.service.repositories.common;

import net.borlis.sample.service.db.em.Simple;
import net.borlis.sample.service.db.update.Schema;
import net.borlis.sample.service.entities.configuration.interfaces.IVitoEntity;
import net.borlis.sample.service.entities.customer.DynamixAccountEntity;
import net.borlis.sample.service.entities.customer.DynamixCustomerEntity;
import net.borlis.sample.service.entities.general.PaymentSystemEntity;
import junit.framework.Assert;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import java.util.logging.Logger;

import static net.borlis.dictionaries.product.LifecycleStateDictionary.WORKING_COPY;

/**
* @author alex@borlis.net on 11.06.2014.
*/
public abstract class RepoDemoEnvCleaner {

    private static final String DELETE_FROM = "delete from ";

    @Inject
    private Logger logger;

    @Inject @Simple
    private EntityManager em;

    @Inject
    private TestRepoProvider repoProvider;

    @Inject
    private RepoContextProvider contextProvider;

    public void clearStagingData(String tablePrefix, String schemaName) {
        try {
            em.getTransaction().begin();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_provider_config_x_travel_duration").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_provider_x_booking_info").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_provider_configuration").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_provider").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_configuration").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".travel_period").executeUpdate();

            em.createNativeQuery(DELETE_FROM + schemaName + ".vito").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".attached_suborganisation").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".attached_main_organisation").executeUpdate();
            em.getTransaction().commit();
        } catch (Exception error) {
            if (em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
            Assert.fail("Error cleaning Staging data"  + error.getMessage());
        }
    }

    public void clearStagingConfig(String tablePrefix, String schemaName) {
        try {
            em.getTransaction().begin();
            em.createNativeQuery(DELETE_FROM + schemaName + ".bank_detail").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".credit_card_detail").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_address").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".vito_payment_system").executeUpdate();
            em.createNativeQuery(DELETE_FROM + schemaName + ".manual_booking_strategy").executeUpdate();
            em.getTransaction().commit();
        } catch (Exception error) {
            if (em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
            Assert.fail("Error cleaning Staging config : " + error.getMessage());
        }
    }

    public void clearStagingTables() {
        //todo:: uncomment when vito_address, bank and credit card details will be implemented
        clearStagingConfig(Schema.WAITING_FOR_UPLOAD, Schema.WAITING_FOR_UPLOAD_CONFIG);
        clearStagingConfig(Schema.LIVE_COPY, Schema.LIVE_COPY_CONFIG);
        clearStagingConfig(Schema.LAST_LIVE, Schema.LAST_LIVE_CONFIG);
    }

    private void clearLifecycleSchema() {

        //todo :: add rollback here!!!
        repoProvider.getLifecycleActionRepository().beginTransaction();
        repoProvider.getLifecycleActionRepository().deleteAll();
        repoProvider.getLifecycleActionRepository().commitTransaction();

        repoProvider.getLifecycleRepository().beginTransaction();
        repoProvider.getLifecycleRepository().deleteAll();
        repoProvider.getLifecycleRepository().commitTransaction();
    }

    public void clearEnvironment() {

        logger.info(contextProvider.showStatus());
        logger.info("clear the db -> started");

        em.getTransaction().begin();
        em.createNativeQuery(DELETE_FROM + Schema.HISTORY_SCHEMA + ".history_logger").executeUpdate();
        em.createNativeQuery(DELETE_FROM + Schema.HISTORY_SCHEMA + ".configuration_history").executeUpdate();
        em.getTransaction().commit();

        // logger.info(contextProvider.showStatus());
        logger.info("clear the db -> started");

        clearStagingData(Schema.WAITING_FOR_UPLOAD, Schema.WAITING_FOR_UPLOAD_CONFIG);
        clearStagingData(Schema.LIVE_COPY, Schema.LIVE_COPY_CONFIG);
        clearStagingData(Schema.LAST_LIVE, Schema.LAST_LIVE_CONFIG);
        clearLifecycleSchema();

        em.getTransaction().begin();
        repoProvider.getVitoProviderConfigXTravelDurationRepository(WORKING_COPY).deleteAll();
        //first delete VITO-provider configuration
        repoProvider.getVitoProviderDefaultSettingsXTravelDurationRepository(WORKING_COPY).deleteAll();
        repoProvider.getVitoProviderConfigurationRepository(WORKING_COPY).deleteAll();
        repoProvider.getVitoProviderXVitoBookingInfoRepository(WORKING_COPY).deleteAll();
        repoProvider.getVitoPaymentSystemRepository(WORKING_COPY).deleteAll();
        //repoProvider.getPaymentSystemRepository().deleteAll();
        //then vito_provider goes cause vito_provider_configuration depends on it
        repoProvider.getVitoProviderRepository(WORKING_COPY).deleteAll();


        repoProvider.getVitoProviderDefaultSettingsRepository(WORKING_COPY).deleteAll();
        repoProvider.getTravelPeriodRepository(WORKING_COPY).deleteAll();
        repoProvider.getTravelDurationRepository().deleteAll();

        repoProvider.getVitoPaymentSystemRepository(WORKING_COPY).deleteAll();
        repoProvider.getDynamixAccountRepository().deleteAll();
        repoProvider.getDynamixCustomerRepository().deleteAll();
        repoProvider.getVitoAddressRepository(WORKING_COPY).deleteAll();

        repoProvider.getManualBookingStrategyRepository(WORKING_COPY).deleteAll();
        //and finally vito_configuration deletes(first relation between VITO & Provider)
        repoProvider.getVitoConfigurationRepository(WORKING_COPY).deleteAll();
        em.getTransaction().commit();

        clearStagingTables();

        em.getTransaction().begin();
        //so you can delete providers finally
        repoProvider.getTypedDynamixProviderRepository().deleteAll();
        repoProvider.getDynamixProviderDetailRepository().deleteAll();
        repoProvider.getDynamixProviderRepository().deleteAll();
        repoProvider.getProviderRepository().deleteAll();

        //then delete dictionaries nad VITO itself
        //repoProvider.getPaymentSystemRepository().deleteAll();
        repoProvider.getCombinedRepository().deleteAll();
        repoProvider.getSubtypeRepository().deleteAll();
        //repoProvider.getTypeRepository().deleteAll();
        repoProvider.getCombinedBookingStrategyRepository().deleteAll();
        repoProvider.getBookingStrategyRepository().deleteAll();
        repoProvider.getBookingStrategyDecisionRepository().deleteAll();
        repoProvider.getBookingStrategyTypeRepository().deleteAll();
        repoProvider.getVitoRepository(WORKING_COPY).deleteAll();
        repoProvider.getMainOrganisationRepository(WORKING_COPY).deleteAll();

        repoProvider.getCountryDetailRepository().deleteAll();
        repoProvider.getCountryRepository().deleteAll();
        repoProvider.getCurrencyDetailRepository().deleteAll();
        repoProvider.getCurrencyRepository().deleteAll();

        //was commented because we cant delete all - test expects that locales will be created by liquibase scripts
        //dynamixLocaleRepository.deleteAll();

        em.getTransaction().commit();

        em.getTransaction().begin();
        repoProvider.getVitoXDynamixCustomerRepository().deleteAll();
        repoProvider.getVitoXDynamixAccountRepository().deleteAll();
        repoProvider.getDynamixAccountRepository().deleteAll();
        repoProvider.getDynamixCustomerRepository().deleteAll();
        em.getTransaction().commit();
        logger.info("clear the db -> finished");
    }

    protected IVitoEntity createVito(DynamixAccountEntity account) {
        IVitoEntity vito = RepoEntityCreator.createVito(account);
        em.getTransaction().begin();
        repoProvider.getVitoRepository(WORKING_COPY).create(vito);
        em.getTransaction().commit();
        return vito;
    }

    protected DynamixAccountEntity createDynamixAccount() {
        DynamixCustomerEntity dynamixCustomer =
                new DynamixCustomerEntity("MAV", "The test dynamix customer for the maverick account.");
        em.getTransaction().begin();
        getRepoProvider().getDynamixCustomerRepository().create(dynamixCustomer);
        em.getTransaction().commit();
        DynamixAccountEntity dynamixAccount = RepoEntityCreator.createDynamixAccount();
        dynamixAccount.setDynamixCustomer(dynamixCustomer);
        em.getTransaction().begin();
        repoProvider.getDynamixAccountRepository().create(dynamixAccount);
        em.getTransaction().commit();
        return dynamixAccount;
    }

    protected DynamixCustomerEntity createDynamixCustomer() {
        DynamixCustomerEntity dynamixCustomer = RepoEntityCreator.createDynamixCustomer();
        em.getTransaction().begin();
        repoProvider.getDynamixCustomerRepository().create(dynamixCustomer);
        em.getTransaction().commit();
        return dynamixCustomer;
    }

    protected PaymentSystemEntity createPaymentSystem() {
        PaymentSystemEntity paymentSystem = RepoEntityCreator.createPaymentSystem();
        em.getTransaction().begin();
        repoProvider.getPaymentSystemRepository().create(paymentSystem);
        em.getTransaction().commit();
        return paymentSystem;
    }

    public EntityManager getEm() {
        return em;
    }

    public TestRepoProvider getRepoProvider() {
        return repoProvider;
    }

}
